#include <gflags/gflags.h>
#include <gtest/gtest.h>

#include <memory>
#include <string>
#include <thread>
#include <vector>

#include "file_io.h"
#include "file_server.h"
#include "channel.h"
#include "log.h"

DEFINE_int32(level, 1, "日志等级");
DEFINE_bool(mode, false, "调试模式-false, 发布模式-true");
DEFINE_string(path, "./logfile", "发布模式下日志输出到的文件路径");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "etcd服务器地址");
DEFINE_string(file_service, "/service/file", "rpc请求目录");

chat::ServiceChannel::ChannelPtr g_channel = nullptr;
std::string single_file_id;

void put_cb(std::string service_name, std::string service_host) {
    LOG_DEBUG("上线服务: {}-{}", service_name, service_host);
}

void del_cb(std::string service_name, std::string service_host) {
    LOG_DEBUG("下线服务: {}-{}", service_name, service_host);
}

TEST(put_test, single_file) {
    // 发起 RPC 调用
    chat::FileService_Stub stub(g_channel.get());

    chat::PutSingleFileReq req;
    chat::PutSingleFileRsp* resp = new chat::PutSingleFileRsp;

    std::string file_content;
    ASSERT_TRUE(chat::File::read("Makefile", &file_content));
    auto file_data = req.mutable_file_data();
    file_data->set_file_name("Makefile");
    file_data->set_file_content(file_content);
    file_data->set_file_size(file_content.size());
    req.set_request_id("1111");

    brpc::Controller* controller = new brpc::Controller;

    stub.PutSingleFile(controller, &req, resp, nullptr);  // 同步调用
    ASSERT_FALSE(controller->Failed());

    ASSERT_TRUE(resp->success());
    ASSERT_EQ(resp->file_info().file_size(), file_content.size());
    ASSERT_EQ(resp->file_info().file_name(), "Makefile");
    single_file_id = resp->file_info().file_id();
    LOG_DEBUG("文件ID: {}", resp->file_info().file_id());
}

TEST(get_test, single_file) {
    // 先发起Rpc调用，进行文件下载
    chat::FileService_Stub stub(g_channel.get());
    chat::GetSingleFileReq req;
    chat::GetSingleFileRsp* rsp;
    req.set_request_id("2222");
    req.set_file_id(single_file_id);

    brpc::Controller* cntl = new brpc::Controller();
    rsp = new chat::GetSingleFileRsp();
    stub.GetSingleFile(cntl, &req, rsp, nullptr);
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(rsp->success());
    // 将文件数据，存储到文件中
    ASSERT_EQ(single_file_id, rsp->file_data().file_id());
    chat::File::write("make_file_download", rsp->file_data().file_content());
}

std::vector<std::string> multi_file_id;

TEST(put_test, multi_file) {
    // 1. 读取当前目录下的指定文件数据
    std::string body1;
    ASSERT_TRUE(chat::File::read("./base.pb.h", &body1));
    std::string body2;
    ASSERT_TRUE(chat::File::read("./file.pb.h", &body2));
    // 2. 实例化rpc调用客户端对象，发起rpc调用
    chat::FileService_Stub stub(g_channel.get());

    chat::PutMultiFileReq req;
    req.set_request_id("3333");

    auto file_data = req.add_file_data();
    file_data->set_file_name("base.pb.h");
    file_data->set_file_size(body1.size());
    file_data->set_file_content(body1);

    file_data = req.add_file_data();
    file_data->set_file_name("file.pb.h");
    file_data->set_file_size(body2.size());
    file_data->set_file_content(body2);

    brpc::Controller* cntl = new brpc::Controller();
    chat::PutMultiFileRsp* rsp = new chat::PutMultiFileRsp();
    stub.PutMultiFile(cntl, &req, rsp, nullptr);
    ASSERT_FALSE(cntl->Failed());
    // 3. 检测返回值中上传是否成功
    ASSERT_TRUE(rsp->success());
    for (int i = 0; i < rsp->file_info_size(); i++) {
        multi_file_id.push_back(rsp->file_info(i).file_id());
        LOG_DEBUG("文件ID: {}", multi_file_id[i]);
    }
}

TEST(get_test, multi_file) {
    // 先发起Rpc调用，进行文件下载
    chat::FileService_Stub stub(g_channel.get());
    chat::GetMultiFileReq req;
    chat::GetMultiFileRsp* rsp;
    req.set_request_id("4444");
    req.add_file_id_list(multi_file_id[0]);
    req.add_file_id_list(multi_file_id[1]);

    brpc::Controller* cntl = new brpc::Controller();
    rsp = new chat::GetMultiFileRsp();
    stub.GetMultiFile(cntl, &req, rsp, nullptr);
    ASSERT_FALSE(cntl->Failed());
    ASSERT_TRUE(rsp->success());
    // 将文件数据，存储到文件中
    for (auto& str : multi_file_id) {
        std::cout << str << std::endl;
    }

    for (auto& it : rsp->file_data()) {
        std::cout << it.first << std::endl;
    }
    ASSERT_TRUE(rsp->file_data().find(multi_file_id[0]) !=
                rsp->file_data().end());
    ASSERT_TRUE(rsp->file_data().find(multi_file_id[1]) !=
                rsp->file_data().end());
    auto map = rsp->file_data();
    auto file_data1 = map[multi_file_id[0]];
    chat::File::write("base_download_file1", file_data1.file_content());
    auto file_data2 = map[multi_file_id[1]];
    chat::File::write("file_download_file2", file_data2.file_content());
}

int main(int argc, char* argv[]) {
    testing::InitGoogleTest(&argc, argv);   //初始化
    gflags::ParseCommandLineFlags(&argc, &argv, true);
    chat::initLogger(FLAGS_level, FLAGS_mode, FLAGS_path);

    // 1. 构造 RPC 服务管理对象
    chat::ServiceManagerPtr service_manager =
        std::make_shared<chat::ServiceManager>();
    service_manager->declared(FLAGS_file_service);  // 添加关心

    // 2. 构造服务发现对象
    auto discovery = std::make_shared<chat::Discovery>(
        FLAGS_etcd_host, FLAGS_file_service,
        std::bind(&chat::ServiceManager::onServiceOnline, service_manager.get(),
                  std::placeholders::_1, std::placeholders::_2),
        std::bind(&chat::ServiceManager::onServiceOffline,
                  service_manager.get(), std::placeholders::_1,
                  std::placeholders::_2));

    // 3. 通过 RPC 信道管理对象，获取提供 Echo 服务的信道
    g_channel = service_manager->choose(FLAGS_file_service);
    if (g_channel == nullptr) {
        LOG_ERROR("没有能够提供 {} 的主机", FLAGS_file_service);

        return -1;
    }

    return RUN_ALL_TESTS();
}